package com.example.jimuyutabletcontrol.activity;

import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.graphics.Color;
import android.graphics.Point;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;

import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.BitmapDescriptorFactory;
import com.baidu.mapapi.map.CircleOptions;
import com.baidu.mapapi.map.MapStatus;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.MarkerOptions;
import com.baidu.mapapi.map.MyLocationData;
import com.baidu.mapapi.map.Overlay;
import com.baidu.mapapi.map.OverlayOptions;
import com.baidu.mapapi.map.PolylineOptions;
import com.baidu.mapapi.map.TextOptions;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.utils.DistanceUtil;
import com.example.jimuyutabletcontrol.R;
import com.example.jimuyutabletcontrol.network.udp.UdpMessageHandle;
import com.example.jimuyutabletcontrol.network.udp.UdpMessageType;
import com.example.jimuyutabletcontrol.network.udp.UdpSocket;
import com.example.jimuyutabletcontrol.sensor.LocationSensor;
import com.example.jimuyutabletcontrol.utils.Constants;
import com.example.jimuyutabletcontrol.utils.Tools;
import com.google.android.material.floatingactionbutton.FloatingActionButton;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import androidx.appcompat.app.AppCompatActivity;

public class DotActivity extends AppCompatActivity implements View.OnClickListener {

    private MapView mapView;
    private BaiduMap baiduMap;
    private List<LatLng> distancePoints;
    private ArrayList<Overlay> distanceOverlay;
    private Overlay polyline;
    private Overlay mText;
    private LocationClient mLocationClient;

    private ArrayList<Integer> colorList;
    private int colorCount = 0;
    private Button startLocation;
    private Button stopLocation;
    private LocationSensor locationSensor;
    private SailTaskActivity sailTaskActivity;
    private DotActivity.MyLocationListener myLocationListener;

    private static DotActivity self;
    private UdpMessageHandle handle;

    public static DotActivity getInstance() {
        return self;
    }

    private Point[] pentagonVertices;
    private FloatingActionButton fabTools;
    private Button[] buttonsTools;
    private int startPositionX;
    private int startPositionY;
    private int toolsWhichAnimation;
    private int[] enterDelay = {0, 40, 80, 120, 160, 200, 240};
    private int[] exitDelay = {0, 40, 80, 120, 160, 200, 240};
    private Boolean isFabToolsClicked = false;


    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.dotinterface_activity);

        mapView = findViewById(R.id.bmapViewdot);
        baiduMap = mapView.getMap();

        //startLocation = findViewById(R.id.startcontinuelocation);
        //stopLocation = findViewById(R.id.stopcontinuelocation);

        setBaseMapConf();
        setLocationRegister();
        initResource();
        setClickListener();
        updateCollectDot();
        prepareFloatButton();

        self = this;
        setListeners();
    }

    private void setListeners() {
        handle = new UdpMessageHandle(UdpMessageType.LOCATION, this::refreshDot);
        UdpSocket.getInstance().setMessageCallback(handle);
    }

    private void prepareFloatButton() {
        startPositionX = 0;
        startPositionY = 0;
        toolsWhichAnimation = 0;
        fabTools = findViewById(R.id.fabdottool);

        fabTools.setOnClickListener(this);

        pentagonVertices = new Point[10];
        pentagonVertices[0] = new Point(10, 100);
        pentagonVertices[1] = new Point(10, 280);
        pentagonVertices[2] = new Point(10, 460);
        pentagonVertices[3] = new Point(10, 640);
        pentagonVertices[4] = new Point(10, 820);
        pentagonVertices[5] = new Point(10, 1000);
        pentagonVertices[6] = new Point(10, 1180);

        String[] contentTools = {"连续定位", "结束定位", "清除测距"};

        buttonsTools = calculatePentagonVertices(3, contentTools);
    }

    private Button[] calculatePentagonVertices(int number, String[] content) {

        Button[] buttons = new Button[number];

        for (int i = 0; i < buttons.length; i++) {
            //Adding button at (0,0) coordinates and setting their visibility to zero
            buttons[i] = new Button(DotActivity.this);
            buttons[i].setLayoutParams(new RelativeLayout.LayoutParams(100, 100));
            buttons[i].setX(0);
            buttons[i].setY(0);
            buttons[i].setTag(i);
            buttons[i].setOnClickListener(this);
            buttons[i].setVisibility(View.INVISIBLE);
            buttons[i].setBackgroundResource(R.drawable.circular_background);
            buttons[i].setTextColor(Color.DKGRAY);
            buttons[i].setText(content[i]);
            buttons[i].setTextSize(14);
            /**
             * Adding those buttons in acitvities layout
             */
            ((LinearLayout) findViewById(R.id.dot_main)).addView(buttons[i]);
        }

        return buttons;
    }

    private void playEnterAnimation(final Button button, int position) {

        /**
         * Animator that animates buttons x and y position simultaneously with size
         */
        AnimatorSet buttonAnimator = new AnimatorSet();

        /**
         * ValueAnimator to update x position of a button
         */
        ValueAnimator buttonAnimatorX = ValueAnimator.ofFloat(startPositionX,
                pentagonVertices[position].x);
        buttonAnimatorX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                button.setX((float) animation.getAnimatedValue());
                button.requestLayout();
            }
        });
        buttonAnimatorX.setDuration(300);

        /**
         * ValueAnimator to update y position of a button
         */
        ValueAnimator buttonAnimatorY = ValueAnimator.ofFloat(startPositionY,
                pentagonVertices[position].y);
        buttonAnimatorY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                button.setY((float) animation.getAnimatedValue());
                button.requestLayout();
            }
        });
        buttonAnimatorY.setDuration(300);

        /**
         * This will increase the size of button
         */
        ValueAnimator buttonSizeAnimator = ValueAnimator.ofInt(6, 170);
        buttonSizeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                button.getLayoutParams().width = (int) animation.getAnimatedValue();
                button.getLayoutParams().height = (int) animation.getAnimatedValue();
                button.requestLayout();
            }
        });
        buttonSizeAnimator.setDuration(300);

        /**
         * Add both x and y position update animation in
         *  animator set
         */
        buttonAnimator.play(buttonAnimatorX).with(buttonAnimatorY).with(buttonSizeAnimator);
        buttonAnimator.setStartDelay(enterDelay[position]);
        buttonAnimator.start();
    }

    private void playExitAnimation(final Button button, int position) {

        /**
         * Animator that animates buttons x and y position simultaneously with size
         */
        AnimatorSet buttonAnimator = new AnimatorSet();

        /**
         * ValueAnimator to update x position of a button
         */
        ValueAnimator buttonAnimatorX = ValueAnimator.ofFloat(pentagonVertices[position].x,
                startPositionX);
        buttonAnimatorX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                button.setX((float) animation.getAnimatedValue());
                button.requestLayout();
            }
        });
        buttonAnimatorX.setDuration(300);

        /**
         * ValueAnimator to update y position of a button
         */
        ValueAnimator buttonAnimatorY = ValueAnimator.ofFloat(pentagonVertices[position].y,
                startPositionY);
        buttonAnimatorY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                button.setY((float) animation.getAnimatedValue());
                button.requestLayout();
            }
        });
        buttonAnimatorY.setDuration(300);

        /**
         * This will decrease the size of button
         */
        ValueAnimator buttonSizeAnimator = ValueAnimator.ofInt(170, 6);
        buttonSizeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                button.getLayoutParams().width = (int) animation.getAnimatedValue();
                button.getLayoutParams().height = (int) animation.getAnimatedValue();
                button.requestLayout();
            }
        });
        buttonSizeAnimator.setDuration(300);

        /**
         * Add both x and y position update animation in
         *  animator set
         */
        buttonAnimator.play(buttonAnimatorX).with(buttonAnimatorY).with(buttonSizeAnimator);
        buttonAnimator.setStartDelay(exitDelay[position]);
        buttonAnimator.start();
    }

    @Override
    public void onClick(View view) {
        boolean isToolsSubClicked = false;

        switch (view.getId()) {
            case R.id.fabdottool:
                isToolsSubClicked = true;
                isFabToolsClicked = true;
                if (toolsWhichAnimation == 0) {
                    /**
                     * Getting the center point of floating action button
                     *  to set start point of buttons
                     */
                    startPositionX = 2600;
                    startPositionY = 0;

                    for (Button button : buttonsTools) {
                        button.setX(startPositionX);
                        button.setY(startPositionY);
                        button.setVisibility(View.VISIBLE);
                    }
                    for (int i = 0; i < buttonsTools.length; i++) {
                        playEnterAnimation(buttonsTools[i], i);
                    }
                    toolsWhichAnimation = 1;
                } else {
                    for (int i = 0; i < buttonsTools.length; i++) {
                        playExitAnimation(buttonsTools[i], i);
                    }
                    toolsWhichAnimation = 0;
                    isFabToolsClicked = false;
                }
                break;
        }
        if (isFabToolsClicked && !isToolsSubClicked) {
            switch ((int) view.getTag()) {
                case 0:
                    buttonsTools[0].setEnabled(false);
                    buttonsTools[0].setBackgroundResource(R.drawable.disable_circular_background);
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            if (!sailTaskActivity.mappingRecord) {
                                locationSensor.startLocation();
                                sailTaskActivity.mappingRecord = true;
                            }
                            while (sailTaskActivity.mappingRecord) {
                                try {
                                    Thread.sleep(5000);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }

                                double[] values = locationSensor.getValue();

                                //if (updateLatitude != values[1] || updateLongtitude != values[0]) {
                                baiduMap.addOverlay(new CircleOptions().center(
                                        Tools.gpsToBaidu(new LatLng(values[1], values[0])))
                                        .fillColor(0xff000000).radius(4));
                                //    updateLongtitude = values[0];
                                //    updateLatitude = values[1];
                                //}
                            }

                            if (DotActivity.this != null) {
                                DotActivity.this.runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        buttonsTools[0].setEnabled(true);
                                        buttonsTools[0].setBackgroundResource(R.drawable.circular_background);
                                        buttonsTools[1].setEnabled(true);
                                        buttonsTools[1].setBackgroundResource(R.drawable.circular_background);
                                    }
                                });
                            }
                        }
                    }).start();
                    break;
                case 1:
                    if (sailTaskActivity.mappingRecord) {
                        sailTaskActivity.mappingRecord = false;
                        locationSensor.stopLocation();
                        buttonsTools[1].setEnabled(false);
                        buttonsTools[1].setBackgroundResource(R.drawable.disable_circular_background);
                    } else {
                        toastMsg("无连续定位任务");
                    }
                    break;
                case 2:
                    if (distancePoints.size() != 0) {
                        distancePoints.clear();
                        distancePoints = new ArrayList<>();
                        for (Overlay overlay : distanceOverlay) {
                            overlay.remove();
                        }
                        distanceOverlay.clear();
                        distanceOverlay = new ArrayList<>();
                    }
                    if (polyline != null) {
                        polyline.remove();
                        polyline = null;
                    }
                    if (mText != null) {
                        mText.remove();
                    }
                    break;
            }
        }
    }

    private void updateCollectDot() {
        if (Constants.auvDots != null && Constants.auvDots.size() != 0) {
            for (Map.Entry<String, ArrayList<LatLng>> entry : Constants.auvDots.entrySet()) {
                for (LatLng point : entry.getValue()) {
                    baiduMap.addOverlay(new CircleOptions().center(
                            Tools.gpsToBaidu(point))
                            .fillColor(Constants.auvColors.get(entry.getKey())).radius(2));
                }
            }
        }
    }

    /*
    private void setClickListener() {
        startLocation.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startLocation.setEnabled(false);
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        if(!sailTaskActivity.mappingRecord) {
                            locationSensor.startLocation();
                            sailTaskActivity.mappingRecord = true;
                        }
                        while (sailTaskActivity.mappingRecord) {
                            try {
                                Thread.sleep(5000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }

                            double[] values = locationSensor.getValue();

                            if (updateLatitude != values[1] || updateLongtitude != values[0]) {
                                baiduMap.addOverlay(new CircleOptions().center(
                                        Tools.gpsToBaidu(new LatLng(values[1], values[0])))
                                        .fillColor(0xff000000).radius(2));
                                updateLongtitude = values[0];
                                updateLatitude = values[1];
                            }
                        }

                        if (DotActivity.this != null) {
                            DotActivity.this.runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    startLocation.setEnabled(true);
                                    stopLocation.setEnabled(true);
                                }
                            });
                        }
                    }
                }).start();
            }
        });

        stopLocation.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (sailTaskActivity.mappingRecord) {
                    sailTaskActivity.mappingRecord = false;
                    locationSensor.stopLocation();
                    stopLocation.setEnabled(false);
                } else {
                    toastMsg("无连续定位任务");
                }
            }
        });
    }
    */

    private void initResource() {
        colorList = new ArrayList<>();
        distancePoints = new ArrayList<>();
        distanceOverlay = new ArrayList<>();

        colorList.add(0xffff0000);
        colorList.add(0xff0000ff);
        colorList.add(0xff00ff00);
        colorList.add(0xffff00ff);
        colorList.add(0xffffff00);
        colorList.add(0xff00ffff);

        colorCount = 0;

        locationSensor = new LocationSensor();
        sailTaskActivity = SailTaskActivity.getInstance();
        //updateLongtitude = 0.0;
        //updateLatitude = 0.0;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        locationSensor.stopLocation();
        if (mLocationClient != null) {
            mLocationClient.unRegisterLocationListener(myLocationListener);
            mLocationClient.stop();
            mLocationClient = null;
        }
        baiduMap.setMyLocationEnabled(false);
        mapView.onDestroy();
        mapView = null;
        self = null;
        if (null != handle) {
            UdpSocket.getInstance().removeMessageCallback(handle);
            handle = null;
        }
    }

    private void setBaseMapConf() {
        baiduMap.clear();

        MapStatus.Builder builder = new MapStatus.Builder();
        builder.zoom(4.0f);
        baiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
    }

    private void setLocationRegister() {
        mLocationClient = new LocationClient(this);

        LocationClientOption option = new LocationClientOption();
        option.setOpenGps(true); // 打开gps
        option.setCoorType("bd09ll"); // 设置坐标类型
        option.setScanSpan(1000);

        mLocationClient.setLocOption(option);

        myLocationListener = new DotActivity.MyLocationListener();
        mLocationClient.registerLocationListener(myLocationListener);
        baiduMap.setMyLocationEnabled(true);
        mLocationClient.start();
    }

    private class MyLocationListener extends BDAbstractLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {

            //mapView 销毁后不在处理新接收的位置
            if (location == null || mapView == null) {
                return;
            }
            MyLocationData locData = new MyLocationData.Builder()
                    .accuracy(location.getRadius())
                    // 此处设置开发者获取到的方向信息，顺时针0-360
                    .direction(location.getDirection()).latitude(location.getLatitude())
                    .longitude(location.getLongitude()).build();
            baiduMap.setMyLocationData(locData);
            MapStatus.Builder builder = new MapStatus.Builder();
            builder.zoom(19.0f);
            baiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
            LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
            MapStatusUpdate status = MapStatusUpdateFactory.newLatLng(ll);
            baiduMap.animateMapStatus(status);//动画的方式到中间
            mLocationClient.stop();
            baiduMap.setMyLocationEnabled(false);
        }
    }

    private void refreshDot(String message) {
        runOnUiThread(()->{
            String[] info = message.split("-");
            if (colorCount < colorList.size() || Constants.auvColors.containsKey(info[2])) {
                if (!Constants.auvColors.containsKey(info[2])) {
                    Constants.auvColors.put(info[2], colorList.get(colorCount));
                    Constants.auvDots.put(info[2], new ArrayList<LatLng>());
                    colorCount++;
                }
                String[] location = info[1].split(",");
                Constants.auvDots.get(info[2]).add(new LatLng(Double.valueOf(location[0]), Double.valueOf(location[1])));
                baiduMap.addOverlay(new CircleOptions().center(
                        Tools.gpsToBaidu(new LatLng(Double.valueOf(location[0]), Double.valueOf(location[1]))))
                        .fillColor(Constants.auvColors.get(info[2])).radius(2));

            } else {
                toastMsg("超出可绘制" + colorList.size() + "个AUV轨迹限制，请联系海防，帮您增加可绘制AUV数量");
            }

        });
    }


    private void setClickListener() {
        BaiduMap.OnMapLongClickListener longClickListener = new BaiduMap.OnMapLongClickListener() {
            @Override
            public void onMapLongClick(LatLng latLng) {
                if (distancePoints != null && distancePoints.size() != 2) {
                    distancePoints.add(latLng);
                    OverlayOptions option = new MarkerOptions().position(latLng)
                            .icon(BitmapDescriptorFactory.fromResource(R.drawable.taskmap_icon_distance));
                    distanceOverlay.add(baiduMap.addOverlay(option));
                }

                if (distancePoints.size() == 2 && polyline == null) {
                    OverlayOptions mOverlayOptions = new PolylineOptions()
                            .width(5)
                            .color(Color.BLACK)
                            .points(distancePoints);
                    polyline = baiduMap.addOverlay(mOverlayOptions);

                    OverlayOptions mTextOptions = new TextOptions()
                            .text("" + DistanceUtil.getDistance(distancePoints.get(0), distancePoints.get(1))) //文字内容
                            .bgColor(0xAAFFFF00) //背景色
                            .fontSize(24) //字号
                            .fontColor(0xFFFF00FF) //文字颜色
                            .position(latLng);

                    mText = baiduMap.addOverlay(mTextOptions);

                    //TODO
                    //showTwoPointDistance.setText(String.valueOf(DistanceUtil.getDistance(distancePoints.get(0), distancePoints.get(1))));
                }
            }
        };
        baiduMap.setOnMapLongClickListener(longClickListener);
    }


    private void toastMsg(final String msg) {
        runOnUiThread(() -> Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show());
    }

}
